home *** CD-ROM | disk | FTP | other *** search
/ Aminet 1 (Walnut Creek) / Aminet - June 1993 [Walnut Creek].iso / aminet / util / gnu / gnu_smalltalk1_2.lha / mstsave.c < prev    next >
C/C++ Source or Header  |  1992-02-15  |  22KB  |  907 lines

  1. /***********************************************************************
  2.  *
  3.  *    Binary image save/restore.
  4.  *
  5.  ***********************************************************************/
  6.  
  7. /***********************************************************************
  8.  *
  9.  * Copyright (C) 1990, 1991, 1992 Free Software Foundation, Inc.
  10.  * Written by Steve Byrne.
  11.  *
  12.  * This file is part of GNU Smalltalk.
  13.  *
  14.  * GNU Smalltalk is free software; you can redistribute it and/or modify it
  15.  * under the terms of the GNU General Public License as published by the Free
  16.  * Software Foundation; either version 1, or (at your option) any later 
  17.  * version.
  18.  * 
  19.  * GNU Smalltalk is distributed in the hope that it will be useful, but WITHOUT
  20.  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
  21.  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  22.  * more details.
  23.  * 
  24.  * You should have received a copy of the GNU General Public License along with
  25.  * GNU Smalltalk; see the file COPYING.  If not, write to the Free Software
  26.  * Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  
  27.  *
  28.  ***********************************************************************/
  29.  
  30.  
  31. /*
  32.  *    Change Log
  33.  * ============================================================================
  34.  * Author      Date       Change 
  35.  * sbb         14 Sep 91      Added support for edit version.
  36.  *
  37.  * sbyrne    17 Apr 90      Fixing binary save to save only to the maximum used
  38.  *              OOP slot, instead of saving the entire OOP table.
  39.  *              This should improve load time and decrease disk
  40.  *              storage requirements.
  41.  *
  42.  * sbyrne    11 Feb 90      Changed the header to record the size of the oop
  43.  *              table, since trying to load back into a system with a
  44.  *              different sized oop table loses bigtime.
  45.  *
  46.  * sbyrne     5 Apr 89      modified to reflect change in classes: now their name
  47.  *              is a Smalltalk string; before, it was a C string that
  48.  *              had to be saved specially.
  49.  *
  50.  * sbyrne     4 Mar 89      Created.
  51.  *
  52.  */
  53.  
  54.  
  55. #include <stdio.h>
  56. #include "mst.h"
  57. #include "mstsave.h"
  58. #include "mstcomp.h"
  59. #include "mstinterp.h"
  60. #include "mstdict.h"
  61. #include "mstsym.h"
  62. #include "mstoop.h"        /* indirectly defines oopAt for sym tab prof */
  63. #include "mstlib.h"
  64. #ifdef HAS_ALLOCA_H
  65. #include <alloca.h>
  66. #endif
  67. #include <stdio.h>
  68.  
  69. #ifndef MAXPATHLEN
  70. #define MAXPATHLEN        1024 /* max length of a file and path */
  71. #endif
  72.  
  73. #define fromBeginning        0 /* symbolic name for file offset modifier */
  74.  
  75. /* convert to a relative offset from start of OOP table */
  76. #define toRelative(obj) \
  77.   ( (OOP)((long)(obj) - (long)oopTable) )
  78.  
  79. /* convert from relative offset to actual oop table address */
  80. #define fromRelative(obj) \
  81.   ( (OOP)((long)(obj) + (long)oopTable) )
  82.  
  83. /* round "x" up to the next 4 byte boundary */
  84. #define roundUpWord(x) \
  85.   ( ((x) + 3) & ~3 )
  86.  
  87. /*
  88.  * The binary image file has the following format:
  89.  *
  90.  *    header
  91.  *    complete oop table
  92.  *    global oop variable data
  93.  *    objects and non-oop object data
  94.  *    char object data
  95.  *    nil object
  96.  *    boolean objects
  97.  */
  98.  
  99.  
  100. typedef struct SaveFileHeaderStruct {
  101.   long        version;    /* the Smalltalk version that made this dump */
  102.   unsigned long    objectDataSize;    /* size of object data section in bytes */
  103.   unsigned long    oopTableSize;    /* size of the oop table at dump */
  104.   unsigned long    semiSpaceSize;    /* size of the semi spaces at dump time */
  105. } SaveFileHeader;
  106.  
  107. typedef struct OOPVectorStruct {
  108.   Object    base;        /* base of the storage */
  109.   Object    ptr;        /* the current object */
  110. } OOPVector;
  111.  
  112.  
  113. OOP        *globalOOPs[] = {
  114.   &andColonSymbol,
  115.   &atColonPutColonSymbol,
  116.   &atColonSymbol,
  117.   &atEndSymbol,
  118.   &bitAndColonSymbol,
  119.   &bitOrColonSymbol,
  120.   &bitShiftColonSymbol,
  121.   &blockCopyColonSymbol,
  122.   &classSymbol,
  123.   ÷Symbol,
  124.   &doColonSymbol,
  125.   &equalSymbol,
  126.   &greaterEqualSymbol,
  127.   &greaterThanSymbol,
  128.   &ifFalseColonIfTrueColonSymbol,
  129.   &ifFalseColonSymbol,
  130.   &ifTrueColonIfFalseColonSymbol,
  131.   &ifTrueColonSymbol,
  132.   &integerDivideSymbol,
  133.   &lessEqualSymbol,
  134.   &lessThanSymbol,
  135.   &minusSymbol,
  136.   &newColonSymbol,
  137.   &newSymbol,
  138.   &nextPutColonSymbol,
  139.   &nextSymbol,
  140.   ¬EqualSymbol,
  141.   ¬SameObjectSymbol,
  142.   &orColonSymbol,
  143.   &plusSymbol,
  144.   &remainderSymbol,
  145.   &sameObjectSymbol,
  146.   &sizeSymbol,
  147.   &thisContextSymbol,
  148.   ×Symbol,
  149.   &valueColonSymbol,
  150.   &valueColonValueColonSymbol,
  151.   &valueColonValueColonValueColonSymbol,
  152.   &valueWithArgumentsColonSymbol,
  153.   &valueSymbol,
  154.   &whileFalseColonSymbol,
  155.   &whileTrueColonSymbol,
  156.   &orSymbol,
  157.   &andSymbol,
  158.   &superSymbol,
  159.   &nilSymbol,
  160.   &trueSymbol,
  161.   &falseSymbol,
  162.   &selfSymbol,
  163.   &doesNotUnderstandColonSymbol,
  164.   &unknownSymbol,
  165.   &charSymbol,
  166.   &stringSymbol,
  167.   &stringOutSymbol, 
  168.   &symbolSymbol,
  169.   &intSymbol,
  170.   &longSymbol,
  171.   &doubleSymbol,
  172.   &voidSymbol,
  173.   &variadicSymbol,
  174.   &cObjectSymbol,
  175.   &smalltalkSymbol,
  176.   &byteArraySymbol,
  177.   &byteArrayOutSymbol,
  178.   &objectClass,
  179.   &magnitudeClass,
  180.   &charClass,
  181.   &timeClass,
  182.   &numberClass,
  183.   &floatClass,
  184.   &integerClass,
  185.   &lookupKeyClass,
  186.   &associationClass,
  187.   &linkClass,
  188.   &processClass,
  189.   &symLinkClass,
  190.   &collectionClass,
  191.   &sequenceableCollectionClass,
  192.   &linkedListClass,
  193.   &semaphoreClass,
  194.   &arrayedCollectionClass,
  195.   &arrayClass,
  196.   &stringClass,
  197.   &symbolClass,
  198.   &byteArrayClass,
  199.   &compiledMethodClass,
  200.   &intervalClass,
  201.   &orderedCollectionClass,
  202.   &sortedCollectionClass,
  203.   &bagClass,
  204.   &mappedCollectionClass,
  205.   &setClass,
  206.   &dictionaryClass,
  207.   &identityDictionaryClass,
  208.   &systemDictionaryClass,
  209.   &undefinedObjectClass,
  210.   &booleanClass,
  211.   &falseClass,
  212.   &trueClass,
  213.   &processorSchedulerClass,
  214.   &delayClass,
  215.   &sharedQueueClass,
  216.   &behaviorClass,
  217.   &classDescriptionClass,
  218.   &classClass,
  219.   &metaclassClass,
  220.   &smalltalkDictionary,
  221.   &messageClass,
  222.   &methodContextClass,
  223.   &blockContextClass,
  224.   &streamClass,
  225.   &positionableStreamClass,
  226.   &readStreamClass,
  227.   &writeStreamClass,
  228.   &readWriteStreamClass,
  229.   &cObjectClass,
  230.   &cTypeClass,
  231.   &fileStreamClass,
  232.   &memoryClass,
  233.   &byteMemoryClass,
  234.   &wordMemoryClass,
  235.   &randomClass,
  236.   &cFuncDescriptorClass,
  237.   &tokenStreamClass,
  238.   &methodInfoClass,
  239.   &fileSegmentClass,
  240.   &nilOOP,
  241.   &trueOOP,
  242.   &falseOOP,
  243.   &processorOOP,
  244.   &symbolTable,
  245.   nil
  246. };
  247.  
  248.  
  249. static void    skipOverHeader(), saveObject(), fixupObject(),
  250.         fixupMethodObject(), restoreObject(), restoreMethodObject(),
  251.         saveOOPTable(), fixupAllOOPs(), fixupOOP(),
  252.         /* fixupFreeOOP(), */restoreAllOOPs(), restoreOOP(), 
  253.         /*restoreFreeOOP(), */loadOOPTable(), loadNormalOOPs(),
  254.         loadCharOOPs(), loadSpecialOOPs(), saveGlobalOOPs(),
  255.         loadGlobalOOPs(), fixupClassObject(), restoreInstanceVars(),
  256.         restoreClassObject(), saveFileVersion(),
  257.         loadFileVersion(), fixupInstanceVars(), fixupOOPInstanceVars();
  258.  
  259. static int    saveNormalOOPs(), saveAllObjects();
  260.  
  261.  
  262. /* This variable contains the OOP slot index of the highest non-free OOP,
  263.  * excluding the built-in ones (i.e., it will always be < OOP_TABLE_SIZE).
  264.  * This is used for optimizing the size of the saved image, and minimizing
  265.  * the load time when restoring the system. */
  266. static int    maxUsedOOPSlot = 0;
  267.  
  268.  
  269. Boolean saveToFile(fileName)
  270. char    *fileName;
  271. {
  272.   FILE        *imageFile;
  273.   unsigned long    objectDataSize;
  274.   Boolean    oldGCState;
  275.  
  276.   realizeMethodContexts();    /* make sure all contexts are real */
  277.  
  278. #ifdef pre_sc_gc /* Sat Jul 27 22:33:36 1991 */
  279. /**/  fullGC();            /* make sure that the world is compact if
  280. /**/                   possible */
  281. /**/
  282. #endif /* pre_sc_gc Sat Jul 27 22:33:36 1991 */
  283.   gcFlip();            /* make sure that the world is compact if
  284.                  * possible */
  285.   oldGCState = gcOff();
  286.  
  287. #ifdef BINARY_MODE_NEEDED
  288.   imageFile = fopen(fileName, "wb");
  289. #else
  290.   imageFile = fopen(fileName, "w");
  291. #endif
  292.   if (imageFile == NULL) {
  293.     errorf("Couldn't open file %s", fileName);
  294.     return (false);
  295.   }
  296.  
  297.   skipOverHeader(imageFile);
  298.   saveOOPTable(imageFile);
  299.  
  300. #ifdef OOP_TABLE_TRACE
  301. printf("After saving oopt table: %d\n", ftell(imageFile));
  302. #endif /* OOP_TABLE_TRACE */
  303.  
  304.   saveGlobalOOPs(imageFile);
  305.  
  306. #ifdef OOP_TABLE_TRACE
  307. printf("After global oop table: %d\n", ftell(imageFile));
  308. #endif /* OOP_TABLE_TRACE */
  309.  
  310.   objectDataSize = saveAllObjects(imageFile);
  311.  
  312. #ifdef OOP_TABLE_TRACE
  313. printf("After saving all objects table: %d\n", ftell(imageFile));
  314. #endif /* OOP_TABLE_TRACE */
  315.  
  316.   skipToHeader(imageFile);
  317.   saveFileVersion(imageFile, objectDataSize);
  318.  
  319.   fclose(imageFile);
  320.  
  321.   setGCState(oldGCState);
  322.   return (true);
  323.  
  324.  
  325. static void skipOverHeader(imageFile)
  326. FILE    *imageFile;
  327. {
  328.   fseek(imageFile, sizeof(SaveFileHeader), fromBeginning);
  329. }
  330.  
  331. /*
  332.  *    static void saveOOPTable(imageFile)
  333.  *
  334.  * Description
  335.  *
  336.  *    Writes the OOP table out to the image file.  We need to make all
  337.  *    of the object pointers relative, including free OOP table slots, and
  338.  *    we use a parallel vector containing file offsets for the objects that
  339.  *    we developed during saving of the objects themselves as the fixup
  340.  *    table.
  341.  *
  342.  * Inputs
  343.  *
  344.  *    imageFile: 
  345.  *        A stdio FILE to be written to.  It must be positioned
  346.  *        correctly before this routine is called.
  347.  *
  348.  */
  349. static void saveOOPTable(imageFile)
  350. FILE    *imageFile;
  351. {
  352.   fixupAllOOPs();
  353.  
  354. #ifdef OOP_TABLE_TRACE
  355. printf("there are %d free oops out of %d oops, leaving %d\n",
  356.        numFreeOOPs, OOP_TABLE_SIZE, OOP_TABLE_SIZE - numFreeOOPs);
  357. printf("max used is %d\n", maxUsedOOPSlot);
  358. #endif /* OOP_TABLE_TRACE */
  359.  
  360.   /* save up to the max oop slot in use */
  361.   fwrite(oopTable, sizeof(struct OOPStruct), maxUsedOOPSlot + 1, imageFile);
  362.  
  363.   /* then save the constant ones at the end */
  364.   fwrite(&oopTable[OOP_TABLE_SIZE], sizeof(struct OOPStruct),
  365.      TOTAL_OOP_TABLE_SLOTS - OOP_TABLE_SIZE, imageFile);
  366.  
  367.   restoreAllOOPs();
  368. }
  369.  
  370.  
  371. static void fixupAllOOPs()
  372. {
  373.   int        i;
  374.  
  375.   maxUsedOOPSlot = 0;
  376.  
  377.   for (i = 0; i < TOTAL_OOP_TABLE_SLOTS; i++) {
  378.     fixupOOP(i);
  379.   }
  380. }
  381.  
  382. static void fixupOOP(i)
  383. int    i;
  384. {
  385.   OOP        oop;
  386.  
  387.   oop = oopAt(i);
  388.   if (!(oop->flags & F_FREE)) {
  389.     if (i < OOP_TABLE_SIZE) {
  390.       maxUsedOOPSlot = i;
  391.     }
  392.     oop->object = (Object)toRelative(oop->object);
  393.   }
  394. }
  395.  
  396.  
  397.  
  398. static void restoreAllOOPs()
  399. {
  400.   int        i;
  401.  
  402.   for (i = 0; i < TOTAL_OOP_TABLE_SLOTS; i++) {
  403.     restoreOOP(i);
  404.   }
  405. }
  406.  
  407.  
  408.  
  409. static void restoreOOP(i)
  410. int    i;
  411. {
  412.   OOP        oop;
  413.  
  414.   oop = oopAt(i);
  415.   if (!(oop->flags & F_FREE)) {
  416.     oop->object = (Object)fromRelative(oop->object);
  417.   }
  418. }
  419.  
  420. #ifdef old_code /* Tue Apr 17 22:50:39 1990 */
  421. /**/static void restoreFreeOOP(oop)
  422. /**/OOP    oop;
  423. /**/{
  424. /**/  if (oop->object == (Object)-1L) {
  425. /**/    oop->object = nil;
  426. /**/  } else {
  427. /**/    oop->object = (Object)fromRelative(oop->object);
  428. /**/  }
  429. /**/
  430. /**/  if (oop->prevFree == -1L) {
  431. /**/    oop->prevFree = (long)nil;
  432. /**/  } else {
  433. /**/    oop->isFree = 0;
  434. /**/    oop->prevFree = (long)fromRelative(oop->prevFree);
  435. /**/  }
  436. /**/
  437. /**/  oop->isFree = 1;
  438. /**/}
  439. #endif /* old_code Tue Apr 17 22:50:39 1990 */
  440.  
  441.  
  442. static void saveGlobalOOPs(imageFile)
  443. FILE    *imageFile;
  444. {
  445.   OOP        **oopPtr, oop;
  446.  
  447.   for (oopPtr = globalOOPs; *oopPtr; oopPtr++) {
  448.     oop = toRelative(**oopPtr);
  449.     fwrite(&oop, sizeof(OOP), 1, imageFile);
  450.   }
  451. }
  452.  
  453.  
  454. static int saveAllObjects(imageFile)
  455. FILE    *imageFile;
  456. {
  457.   long        objectStart, objectEnd;
  458.   int        i;
  459.   OOP        oop;
  460.  
  461.   objectStart = ftell(imageFile);
  462.   for (i = 0; i < OOP_TABLE_SIZE; i++) {
  463.     oop = oopAt(i);
  464.     if (!(oop->flags & F_FREE)) {
  465. #ifdef pre_sc_gc /* Sun Jul 28 13:31:33 1991 */
  466. /**/    if (oopValid(oop)) {
  467. #endif /* pre_sc_gc Sun Jul 28 13:31:33 1991 */
  468.       saveObject(imageFile, oop);
  469.     }
  470.   }
  471.  
  472.   objectEnd = ftell(imageFile);
  473.  
  474.   /* dump out the character objects, nil, true, and false */
  475.   for (i = OOP_TABLE_SIZE; i < TOTAL_OOP_TABLE_SLOTS; i++) {
  476.     saveObject(imageFile, oopAt(i));
  477.   }
  478.  
  479.   return (objectEnd - objectStart);
  480. }
  481.  
  482. static void saveObject(imageFile, oop)
  483. FILE    *imageFile;
  484. OOP    oop;
  485. {
  486.   Object    object;
  487.   int        numFixed, numIndexed;
  488.   Boolean    hasPointers;
  489.  
  490.   object = oopToObj(oop);
  491.   hasPointers = isPointers(oop);
  492.   numFixed = oopFixedFields(oop);
  493.   numIndexed = numIndexableFields(oop);
  494.  
  495.   fixupObject(oop, hasPointers, numFixed, numIndexed);
  496.   fwrite(object, sizeof(OOP), object->objSize, imageFile);
  497.   restoreObject(oop, hasPointers, numFixed, numIndexed);
  498. }
  499.  
  500. static void fixupObject(oop, hasPointers, numFixed, numIndexed)
  501. OOP    oop;
  502. Boolean    hasPointers;
  503. int    numFixed, numIndexed;
  504. {
  505.   int        i;
  506.   Object    object;
  507.   OOP        instOOP, classOOP;
  508.  
  509.   classOOP = oopClass(oop);
  510.  
  511.   if (classOOP == compiledMethodClass) {
  512.     fixupMethodObject(oop);
  513.   } else {
  514.     if (hasPointers) {
  515.       for (i = 1; i <= numFixed + numIndexed; i++) {
  516.     instOOP = instVarAt(oop, i);
  517.     if (!isInt(instOOP)) {
  518.       instVarAtPut(oop, i, toRelative(instOOP));
  519.     }
  520.       }
  521.     }
  522.   }
  523.  
  524.   object = oopToObj(oop);
  525.   object->objClass = toRelative(object->objClass);
  526. }
  527.  
  528. static void fixupMethodObject(oop)
  529. OOP    oop;
  530. {
  531.   MethodHeader    header;
  532.   int        i;
  533.   OOP        literalOOP, descriptorOOP;
  534.  
  535.   descriptorOOP = getMethodDescriptor(oop);
  536.   if (!isInt(descriptorOOP)) {
  537.     setMethodDescriptor(oop, toRelative(descriptorOOP));
  538.   }
  539.   header = getMethodHeaderExt(oop);
  540.   if (header.headerFlag == 1 || header.headerFlag == 2) {
  541.     /* these have no method literals to fix up, so we ignore them */
  542.     return;
  543.   }
  544.  
  545.   for (i = 0; i < header.numLiterals; i++) {
  546.     literalOOP = methodLiteralExt(oop, i);
  547.     if (!isInt(literalOOP)) {
  548.       storeMethodLiteralNoGC(oop, i, toRelative(literalOOP));
  549.     }
  550.   }
  551. }
  552.  
  553. static void restoreObject(oop, hasPointers, numFixed, numIndexed)
  554. OOP    oop;
  555. Boolean    hasPointers;
  556. int    numFixed, numIndexed;
  557. {
  558.   Object    object;
  559.  
  560.   object = oopToObj(oop);
  561.  
  562.   object->objClass = fromRelative(object->objClass);
  563.  
  564.   restoreInstanceVars(oop, hasPointers, numFixed, numIndexed);
  565. }
  566.  
  567. static void restoreInstanceVars(oop, hasPointers, numFixed, numIndexed)
  568. OOP    oop;
  569. Boolean    hasPointers;
  570. int    numFixed, numIndexed;
  571. {
  572.   register int    i;
  573.   OOP        instOOP, classOOP;
  574.  
  575.   classOOP = oopClass(oop);
  576.   if (classOOP == compiledMethodClass) {
  577.     restoreMethodObject(oop);
  578.   } else {
  579.     if (hasPointers) {
  580.       for (i = 1; i <= numFixed + numIndexed; i++) {
  581.     instOOP = instVarAt(oop, i);
  582.     if (!isInt(instOOP)) {
  583.       instVarAtPut(oop, i, fromRelative(instOOP));
  584.     }
  585.       }
  586.       if (classOOP == cFuncDescriptorClass) {
  587.     restoreCFuncDescriptor(oop); /* in mstcint.c */
  588.       }
  589.     }
  590.   }
  591. }
  592.  
  593. static void restoreMethodObject(oop)
  594. OOP    oop;
  595. {
  596.   MethodHeader    header;
  597.   int        i;
  598.   OOP        literalOOP, descriptorOOP;
  599.  
  600.   descriptorOOP = getMethodDescriptor(oop);
  601.   if (!isInt(descriptorOOP)) {
  602.     setMethodDescriptor(oop, fromRelative(descriptorOOP));
  603.   }
  604.  
  605.   header = getMethodHeaderExt(oop);
  606.   if (header.headerFlag == 1 || header.headerFlag == 2) {
  607.     /* these have no method literals to fix up, so we ignore them */
  608.     return;
  609.   }
  610.  
  611.   for (i = 0; i < header.numLiterals; i++) {
  612.     literalOOP = methodLiteralExt(oop, i);
  613.     if (!isInt(literalOOP)) {
  614.       storeMethodLiteralNoGC(oop, i, fromRelative(literalOOP));
  615.     }
  616.   }
  617. }
  618.  
  619.  
  620. skipToHeader(imageFile)
  621. FILE    *imageFile;
  622. {
  623.   rewind(imageFile);
  624. }
  625.  
  626. static void saveFileVersion(imageFile, objectDataSize)
  627. FILE    *imageFile;
  628. unsigned long objectDataSize;
  629. {
  630.   SaveFileHeader header;
  631.  
  632.   header.version = sysVersMajor * 1000000 + sysVersMinor * 1000 + sysVersEdit;
  633.   header.objectDataSize = objectDataSize;
  634.   header.oopTableSize = maxUsedOOPSlot + 1; /* n slots, numbered 0..n-1 */
  635.   header.semiSpaceSize = maxSpaceSize;
  636.  
  637.   fwrite(&header, sizeof(SaveFileHeader), 1, imageFile);
  638. }
  639.  
  640. static void skipToOOPTable(imageFile)
  641. FILE    *imageFile;
  642. {
  643.   rewind(imageFile);
  644. }
  645.  
  646.  
  647. /***********************************************************************
  648.  *
  649.  *    Binary loading routines.
  650.  *
  651.  ***********************************************************************/
  652.  
  653.  
  654. Boolean loadFromFile(fileName)
  655. char    *fileName;
  656. {
  657.   FILE        *imageFile;
  658.   SaveFileHeader header;
  659.   OOPVector    ov;
  660.   Boolean    oldGCState;
  661.   char        fullImageName[MAXPATHLEN];
  662.  
  663.   oldGCState = gcOff();
  664.  
  665.   findImageFile(fileName, fullImageName);
  666. #ifdef BINARY_MODE_NEEDED
  667.   imageFile = fopen(fullImageName, "rb");
  668. #else
  669.   imageFile = fopen(fullImageName, "r");
  670. #endif
  671.   if (imageFile == NULL) {
  672.     fclose(imageFile);
  673.     setGCState(oldGCState);
  674.     return (false);
  675.   }
  676.  
  677.   loadFileVersion(imageFile, &header);
  678.   if (header.version != (sysVersMajor * 1000000 + sysVersMinor * 1000
  679.              + sysVersEdit)) {
  680.     /* version mismatch; this image file is invalid */
  681.     fclose(imageFile);
  682.     setGCState(oldGCState);
  683.     return (false);
  684.   }
  685.   
  686.   if (header.semiSpaceSize != maxSpaceSize) {
  687.     growBothSpaces(header.semiSpaceSize);
  688.   }
  689.  
  690. #ifdef old_code /* Tue Apr 17 22:25:33 1990 */
  691. /**/  if (header.oopTableSize != OOP_TABLE_SIZE) {
  692. /**/    return (false);
  693. /**/  }
  694. #endif /* old_code Tue Apr 17 22:25:33 1990 */
  695.  
  696.   allocOOPTable();
  697.   loadOOPTable(imageFile, header.oopTableSize);
  698.  
  699.   loadGlobalOOPs(imageFile);
  700.  
  701.   loadNormalOOPs(imageFile, header.objectDataSize, &ov);
  702.   loadCharOOPs(imageFile);
  703.   loadSpecialOOPs(imageFile);
  704.  
  705.   fixupInstanceVars(&ov);
  706.  
  707.   fclose(imageFile);
  708.  
  709.   setGCState(oldGCState);
  710.  
  711. dictInit();            /* ### TEMP HACK ### */
  712.  
  713.   return (true);
  714. }
  715.  
  716. static void loadFileVersion(imageFile, headerp)
  717. FILE    *imageFile;
  718. SaveFileHeader *headerp;
  719. {
  720.   fread(headerp, sizeof(SaveFileHeader), 1, imageFile);
  721. }
  722.  
  723. static void loadOOPTable(imageFile, oldSlotsUsed)
  724. FILE    *imageFile;
  725. long     oldSlotsUsed;
  726. {
  727.   long        i;
  728.   OOP        oop;
  729.  
  730. /*  fread(oopTable, sizeof(struct OOPStruct), TOTAL_OOP_TABLE_SLOTS, imageFile);*/
  731.  
  732.   /* load in the valid OOP slots from previous dump */
  733.   fread(oopTable, sizeof(struct OOPStruct), oldSlotsUsed, imageFile);
  734.   
  735.   /* mark the remaining ones as available */
  736.   for (i = oldSlotsUsed; i < OOP_TABLE_SIZE; i++) {
  737.     oop = oopAt(i);
  738.     oop->flags = F_FREE;
  739.   }
  740.  
  741.  
  742.   /* read in the constant stuff at the end */
  743.   fread(&oopTable[OOP_TABLE_SIZE], sizeof(struct OOPStruct),
  744.     TOTAL_OOP_TABLE_SLOTS - OOP_TABLE_SIZE, imageFile);
  745.  
  746.   /* the fixup gets handled by load normal oops */
  747. }
  748.  
  749.  
  750. static void loadGlobalOOPs(imageFile)
  751. FILE    *imageFile;
  752. {
  753.   OOP        **oopPtr, oop, *oopVec;
  754.   long        numGlobalOOPs;
  755.  
  756.   for (numGlobalOOPs = 0, oopPtr = globalOOPs; *oopPtr;
  757.        oopPtr++, numGlobalOOPs++);
  758.  
  759.   oopVec = (OOP *)alloca(numGlobalOOPs * sizeof(OOP));
  760.   fread(oopVec, sizeof(OOP), numGlobalOOPs, imageFile);
  761.  
  762.   for (oopPtr = globalOOPs; *oopPtr; oopPtr++, oopVec++) {
  763.     **oopPtr = fromRelative(*oopVec);
  764.   }
  765. #ifdef old_code /* Wed Apr 26 21:15:38 1989 */ /* <<<== what dedication...3 days before my wedding -- SBB */
  766. /**/  /* ??? this could be sped up by using alloca, doing one fread, and then
  767. /**/     iterating through the array */
  768. /**/  for (oopPtr = globalOOPs; *oopPtr; oopPtr++) {
  769. /**/    fread(&oop, sizeof(OOP), 1, imageFile);
  770. /**/    **oopPtr = fromRelative(oop);
  771. /**/  }
  772. #endif /* old_code Wed Apr 26 21:15:38 1989 */
  773. }
  774.  
  775. static void loadNormalOOPs(imageFile, objectDataSize, ovp) 
  776. FILE    *imageFile;
  777. unsigned long objectDataSize;
  778. OOPVector *ovp;
  779. {
  780.   register long    i;
  781.   OOP        oop, prevFreeOOP;
  782.   Object    object, objPtr;
  783.  
  784.   objPtr = curSpaceAddr();
  785.  
  786.   ovp->base = objPtr;
  787.  
  788.   prevFreeOOP = nil;
  789.  
  790.   fread(objPtr, 1, objectDataSize, imageFile);
  791.  
  792. #ifdef pre_sc_gc /* Sat Jul 27 22:32:54 1991 */
  793. /**/  freeOOPs = nil;
  794. #endif /* pre_sc_gc Sat Jul 27 22:32:54 1991 */
  795.   numFreeOOPs = 0;
  796.   for (i = 0; i < OOP_TABLE_SIZE; i++) {
  797.     oop = oopAt(i);
  798.     if (!(oop->flags & F_FREE)) {
  799. #ifdef pre_sc_gc /* Sun Jul 28 13:34:39 1991 */
  800. /**/    if (oopValid(oop)) {
  801. #endif /* pre_sc_gc Sun Jul 28 13:34:39 1991 */
  802.       object = objPtr;
  803.       oop->object = object;
  804.       /* ### should probably make this setting symbolic/abstracted */
  805.       oop->flags &= ~(F_SPACE|F_EVEN|F_ODD);
  806.       oop->flags |= toSpace;
  807.       if (toSpace) {
  808.     oop->flags |= F_ODD;
  809.       } else {
  810.     oop->flags |= F_EVEN;
  811.       }
  812.       object->objClass = fromRelative(object->objClass);
  813.       objPtr = (Object)((long *)object + object->objSize);
  814.     } else if (oop->flags & F_FREE) {
  815.       /* ignore non-free but non-valid...they'll get handled
  816.        * naturally in due time. */
  817.       numFreeOOPs++;
  818.       oop->flags = F_FREE;    /* just free */
  819. #ifdef pre_sc_gc /* Sat Jul 27 22:00:04 1991 */
  820. /**/      if (prevFreeOOP) {    /* forward chain the oop free list */
  821. /**/    prevFreeOOP->object = (Object)oop;
  822. /**/      }
  823. /**/      if (freeOOPs == nil) {    /* free list points at first free oop in
  824. /**/                   OOP table */
  825. /**/    freeOOPs = oop;
  826. /**/      }
  827. /**/      prevFreeOOP = oop;
  828. #endif /* pre_sc_gc Sat Jul 27 22:00:04 1991 */
  829.     }
  830.   }
  831.  
  832. #ifdef pre_sc_gc /* Sat Jul 27 22:00:13 1991 */
  833. /**/  if (prevFreeOOP) {
  834. /**/    prevFreeOOP->object = nil;    /* terminate the free list nicely */
  835. /**/  }
  836. #endif /* pre_sc_gc Sat Jul 27 22:00:13 1991 */
  837.  
  838.   setSpaceInfo(objectDataSize);
  839.   ovp->ptr = objPtr;
  840. }
  841.  
  842. static void loadCharOOPs(imageFile)
  843. FILE    *imageFile;
  844. {
  845.   int        i;
  846.  
  847.   fread(charObjectTable, sizeof(CharObject), NUM_CHAR_OBJECTS, imageFile);
  848.  
  849. /* ### Inconsistency here... using direct refs to oopTable, instead of oopAts
  850.  * like above.  Probably should convert the whole thing to pointers into
  851.  * the oopTable and be done with it.
  852.  */
  853.   for (i = 0; i < NUM_CHAR_OBJECTS; i++) {
  854.     oopTable[i + CHAR_OBJECT_BASE].object = (Object)&charObjectTable[i];
  855.     oopTable[i + CHAR_OBJECT_BASE].flags &= ~F_SPACE;
  856.     oopTable[i + CHAR_OBJECT_BASE].flags |= toSpace;
  857.     charObjectTable[i].objClass = fromRelative(charObjectTable[i].objClass);
  858.   }
  859. }
  860.  
  861. static void loadSpecialOOPs(imageFile)
  862. FILE    *imageFile;
  863. {
  864.   fread(&nilObject, sizeof(struct NilObjectStruct), 1, imageFile);
  865.   nilOOP->object = (Object)&nilObject;
  866.   nilOOP->object->objClass = fromRelative(nilOOP->object->objClass);
  867. /* ### not sure that I can just assign directly into flags...seems ok, though*/
  868.   nilOOP->flags = toSpace;
  869.  
  870.   fread(booleanObjects, sizeof(struct BooleanObjectStruct), 2, imageFile);
  871.   trueOOP->object = (Object)&booleanObjects[0];
  872.   falseOOP->object = (Object)&booleanObjects[1];
  873.   trueOOP->object->objClass = fromRelative(trueOOP->object->objClass);
  874.   falseOOP->object->objClass = fromRelative(falseOOP->object->objClass);
  875.   trueOOP->flags = falseOOP->flags = toSpace;
  876. }
  877.  
  878. static void fixupInstanceVars(ovp)
  879. OOPVector *ovp;
  880. {
  881.   int        i;
  882.   OOP        oop;
  883.  
  884.   for (i = 0; i < TOTAL_OOP_TABLE_SLOTS; i++) {
  885.     oop = oopAt(i);
  886.     if (oopValid(oop)) {
  887.       fixupOOPInstanceVars(oop, ovp);
  888.     }
  889.   }
  890. }
  891.  
  892. static void fixupOOPInstanceVars(oop, ovp)
  893. OOP    oop;
  894. OOPVector *ovp;
  895. {
  896.   int        numFixed, numIndexed;
  897.   Boolean    hasPointers;
  898.  
  899.   hasPointers = isPointers(oop);
  900.   numFixed = oopFixedFields(oop);
  901.   numIndexed = numIndexableFields(oop);
  902.   restoreInstanceVars(oop, hasPointers, numFixed, numIndexed);
  903. }
  904.  
  905.  
  906.